package com.ctsi.filestore.app.rest;


import com.ctsi.commons.util.UtilValidate;
import com.ctsi.filestore.app.params.MultipartFileParam;
import com.ctsi.filestore.app.service.Constants;
import com.ctsi.filestore.app.service.StorageService;
import com.ctsi.filestore.app.vo.ResultStatus;
import com.ctsi.filestore.app.vo.ResultVo;
import com.ctsi.product.service.UploadService;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.*;

@RestController
public class FileStorageRestApi {

    private static final Logger logger = LoggerFactory.getLogger(FileStorageRestApi.class);

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private StorageService storageService;

    @Autowired
    private UploadService uploadService;

    @RequestMapping(value = "/filestore/checkFileMd5", method = RequestMethod.POST)
    public Object checkFileMd5(String md5) throws IOException {
        Object processingObj = stringRedisTemplate.opsForHash().get(Constants.FILE_UPLOAD_STATUS, md5);
        if (processingObj == null) {
            return new ResultVo(ResultStatus.NO_HAVE);
        }
        String processingStr = processingObj.toString();
        boolean processing = Boolean.parseBoolean(processingStr);
        String value = stringRedisTemplate.opsForValue().get(Constants.FILE_MD5_KEY + md5);
        if (processing) {
            // 此时的value 为已经上传的资源ID
            // TODO: 暂时不处理吧，没时间了
            return new ResultVo(ResultStatus.IS_HAVE, value);
        } else {
            File confFile = new File(value);
            byte[] completeList = FileUtils.readFileToByteArray(confFile);
            List<String> missChunkList = new LinkedList<>();
            for (int i = 0; i < completeList.length; i++) {
                if (completeList[i] != Byte.MAX_VALUE) {
                    missChunkList.add(i + "");
                }
            }
            return new ResultVo<>(ResultStatus.ING_HAVE, missChunkList);
        }
    }

    @RequestMapping(value = "/filestore/fileUpload", method = RequestMethod.POST)
    public ResponseEntity fileUpload(MultipartFileParam param, HttpServletRequest request) {
        boolean isMultipart = ServletFileUpload.isMultipartContent(request);
        Map<String,Object> result = new HashMap<>();
        result.put("complete",false);
        if (isMultipart) {
            logger.info("上传文件start。");
            try {
               Map<String,Object> _meta = storageService.uploadFileByMappedByteBuffer(param);
               if (UtilValidate.isNotEmpty(_meta)) {
                    result.put("complete",true);
                    result.putAll(_meta);

                    return ResponseEntity.ok().body(result);
               }
            } catch (IOException e) {
                logger.error("文件上传失败。{}", e);
            }
            logger.info("上传文件end。");
        }
        return ResponseEntity.ok().body(result);
    }

//    @Autowired
//    private GridFsTemplate gridFsTemplate;
//
//    @RequestMapping(value = "/filestore/open/{id}", method = RequestMethod.GET)
//    public void openFile(@PathVariable(value = "id") String id,HttpServletRequest request, HttpServletResponse response) throws IOException {
//        GridFSFile file = gridFsTemplate.findOne(Query.query(GridFsCriteria.where("_id").is(id)));
//        if (file != null) {
//            GridFsResource fs = new GridFsResource(file);
//            long length = file.getLength();
//            long start = 0;
//            long end = length - 1;
//
//            ReadableByteChannel fe = fs.readableChannel();
//
//
//
//            String range = request.getHeader("Range");
//            range = range == null ? "":range;
//
//
//
//            InputStream in = null;
//            OutputStream out = null;
//            try {
//                response.setContentType(fs.getContentType());
//                response.setContentLengthLong(fs.contentLength());
//                response.setHeader("Content-Disposition", "inline; filename=\"" + URLEncoder.encode(fs.getFilename(),"UTF-8") + "\"");
//                 in = fs.getInputStream();
//                 out = response.getOutputStream();
//                IOUtils.copy(in,out);
//            } catch (IOException e) {
//                e.printStackTrace();
//            }finally {
////                try {
////                    in.close();
////                } catch (IOException e) {
////                    e.printStackTrace();
////                }
////                try {
////                    out.close();
////                } catch (IOException e) {
////                    e.printStackTrace();
////                }
//            }
//        }
//    }


    private void sendVideo(HttpServletRequest request, HttpServletResponse response, File file, String fileName) throws FileNotFoundException, IOException {
        RandomAccessFile randomFile = new RandomAccessFile(file, "r");//只读模式
        long contentLength = randomFile.length();
        String range = request.getHeader("Range");
        int start = 0, end = 0;
        if(range != null && range.startsWith("bytes=")){
            String[] values = range.split("=")[1].split("-");
            start = Integer.parseInt(values[0]);
            if(values.length > 1){
                end = Integer.parseInt(values[1]);
            }
        }
        int requestSize = 0;
        if(end != 0 && end > start){
            requestSize = end - start + 1;
        } else {
            requestSize = Integer.MAX_VALUE;
        }

        byte[] buffer = new byte[4096];
        response.setContentType("video/mp4");
        response.setHeader("Accept-Ranges", "bytes");
        response.setHeader("ETag", fileName);
        response.setHeader("Last-Modified", new Date().toString());
        //第一次请求只返回content length来让客户端请求多次实际数据
        if(range == null){
            response.setHeader("Content-length", contentLength + "");
        }else{
            //以后的多次以断点续传的方式来返回视频数据
            response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);//206
            long requestStart = 0, requestEnd = 0;
            String[] ranges = range.split("=");
            if(ranges.length > 1){
                String[] rangeDatas = ranges[1].split("-");
                requestStart = Integer.parseInt(rangeDatas[0]);
                if(rangeDatas.length > 1){
                    requestEnd = Integer.parseInt(rangeDatas[1]);
                }
            }
            long length = 0;
            if(requestEnd > 0){
                length = requestEnd - requestStart + 1;
                response.setHeader("Content-length", "" + length);
                response.setHeader("Content-Range", "bytes " + requestStart + "-" + requestEnd + "/" + contentLength);
            }else{
                length = contentLength - requestStart;
                response.setHeader("Content-length", "" + length);
                response.setHeader("Content-Range", "bytes "+ requestStart + "-" + (contentLength - 1) + "/" + contentLength);
            }
        }
        ServletOutputStream out = response.getOutputStream();
        int needSize = requestSize;
        randomFile.seek(start);
        while(needSize > 0){
            int len = randomFile.read(buffer);
            if(needSize < buffer.length){
                out.write(buffer, 0, needSize);
            } else {
                out.write(buffer, 0, len);
                if(len < buffer.length){
                    break;
                }
            }
            needSize -= buffer.length;
        }
        randomFile.close();
        out.close();

    }


}
